home *** CD-ROM | disk | FTP | other *** search
/ Best of Shareware / Best of PC Windows Shareware 1.0 - Wayzata Technology (7111) (1993).iso / pc / dos / programg / decgif3 / decgif3.bas next >
BASIC Source File  |  1992-08-06  |  19KB  |  665 lines

  1. '*****************************************************************************
  2. '* DECGIF.BAS- A PDS 7.1 & QB4.5 GIF Decompressor With Some Assembly
  3. '* By Rich Geldreich 1992
  4. '* You may use this program for anything you wish, as long as credit
  5. '* is given where credit is due! Thanks.
  6. '* 06-27-92, X Y Rescaler added 07-17-92
  7. '*
  8. '* To make this program compatible with QB4.5, use search and replace
  9. '* to change all of the "SSEG" strings to "VARSEG" strings in this module.
  10. '*
  11. '*
  12. '* The module USEDGIF.BAS demonstrates this program.
  13. '*
  14. '* Any bugs/problems, write or call:
  15. '*
  16. '* Rich Geldreich
  17. '* 410 Market St.
  18. '* Gloucester City, NJ 08030
  19. '* (609)-742-8752
  20.  
  21. DEFINT A-Z
  22.  
  23. 'Procedures in this module:
  24. DECLARE FUNCTION LoadGIF (F$, Vm, ShowType, Xorigin, Yorigin, XScale, YScale)
  25. DECLARE SUB WriteLine ()
  26.  
  27. 'Procedures in SHOWRGB.ASM:
  28. DECLARE SUB ShowRGB (BYVAL PalOffset, BYVAL PalSegment, BYVAL NumColors, BYVAL VGA)
  29.  
  30. 'Procedures in WPIX2.ASM:
  31. DECLARE SUB SetPixels (BYVAL XSkip, A(), BYVAL X, BYVAL Y, BYVAL NumPixels)
  32. DECLARE SUB SetMode (BYVAL Mode)
  33. DECLARE SUB SetWidth (BYVAL ScreenWidth)
  34.  
  35. 'Procedure in RESCALE.ASM:
  36. DECLARE SUB Rescale (A(), B(), BYVAL NumPoints, BYVAL NewScale)
  37.  
  38. 'Procedure in X360x480.ASM:
  39. DECLARE SUB X360x480 ()
  40.  
  41. CONST True = -1, False = 0
  42.  
  43. CONST BufferLength = 10000      'change this if desired- but don't
  44.                                 'make it too low or floppy-based systems
  45.                                 'will suffer(A LOT)
  46. DIM SHARED Pixels(1024)
  47. DIM SHARED PassStep(4), PassStart(4) AS LONG
  48. DIM SHARED ErrorStatus
  49.  
  50. END
  51. DriveError:
  52.     ErrorStatus = True
  53. RESUME NEXT
  54.  
  55. 'Decompression tables
  56. GIFData:
  57.     'MaxCodes(0 to 11)
  58.     DATA 4,8,16,&h20,&h40,&h80,&h100,&h200,&h400,&h800,&h1000,8192
  59.     'CodeMask(1 to 8)
  60.     DATA 1,3,7,15,31,63,127,255
  61.     'Powers2(0 to 14)
  62.     DATA 1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384
  63.  
  64.     'PassStep(0 to 3), PassStart(0 to 3)
  65.     DATA 8,8,4,2,0,4,2,1
  66.  
  67. '******************************************************************************
  68. '* Displays A GIF file.
  69. '*
  70. '* F$ is the filename of the GIF image.
  71. '*
  72. '* Vm is the video mode:
  73. '*    mode 0=320x200x256 vga QB mode 13
  74. '*    mode 1=360x480x256 vga  -non QB-
  75. '*    mode 2=640x480x16  vga QB mode 12
  76. '*    mode 3=320x200x16  ega QB mode 7
  77. '*    mode 4=640x350x16  ega QB mode 9
  78. '* (To use the 360x480x256 mode on a VGA, call the assembly procedure
  79. '* named "X360x480". Don't forget QB doesn't have support for this graphics
  80. '* mode.)
  81. '*
  82. '* ShowType:
  83. '*   0 = Set the palette before the image is decompressed.
  84. '*   1 = Set the palette after the image is decompressed. The entire palette 
  85. '*   used by the GIF file will be set to black so the user doesn't see the 
  86. '*   image while it is being decompressed.
  87. '*
  88. '* Xorigin, Yorigin:
  89. '*   The origin of the image. If Xorigin=50, and Yorigin=-50, then the
  90. '*   image's upper left corner will be at (50,-50). If the image cannot
  91. '*   be seen then LoadGIF will return with an error.
  92. '*
  93. '* Xscale, Yscale:
  94. '*    Resize parameters. Each parameter is actually divided by 256.
  95. '*    If Xscale=128, and Yscale=512, for example, then the image will
  96. '*    be 1/2 as big horizontally and twice as big vertically. If you want
  97. '*    the image to be normal size, then use 256 for both axis. If a parameter
  98. '*    is -1 then that axis will be shrunk or expanded to fit the screen's size.
  99. '*
  100. '*    Let's say Xscale=-1, and Yscale=300. In this particular case, the image 
  101. '*    will fit the screen's horizontal size and will be 300/256 as big 
  102. '*    vertically. If the resized image is too small or big then LoadGIF will 
  103. '*    return an error.
  104. '*
  105. '* If LoadGIF returns...
  106. '*     0 = The image was decompressed successfully
  107. '*     1 = The specified file could not be found
  108. '*     2 = The specified file is not a GIF file, the GIF file had
  109. '*         had a local colormap, or it had an unrecognized format(maby GIF89a)
  110. '*     3 = The GIF file had too many colors for the specified screen
  111. '*     4 = origin or scale error(if the image was totally out of view,
  112. '*         or it was scaled too small or big, for instance)
  113. '*     5 = An error occured while decompressing the image. The image may
  114. '*         be partly visible, however.
  115. '*
  116. FUNCTION LoadGIF (F$, Vm, ShowType, Xorigin, Yorigin, XScale, YScale)
  117.     DIM Prefix(4096), Suffix(4096), OutCode(1024)
  118.     DIM MaxCodes(12), Powers2(16), CodeMask(8)
  119.     DIM Masks(12)
  120.  
  121.     SHARED CurrentPixel, CurrentLine&
  122.     SHARED XStart&, YStart&, YEnd&, ScreenY&
  123.     SHARED MaxLength, XStart, ScreenY, StoredXLength
  124.     SHARED PassNumber, Interlaced, Done
  125.     SHARED SkipX, SkipY
  126.     SHARED ArrayOffset
  127.  
  128.     'used for reading single bytes from GIF file
  129.     DIM ByteBuffer AS STRING * 1
  130.    
  131.     RESTORE GIFData
  132.  
  133.     B = 2: FOR A = 1 TO 12: Masks(A) = B - 1: B = B * 2: NEXT
  134.     FOR A = 0 TO 11: READ MaxCodes(A): NEXT
  135.     FOR A = 1 TO 8: READ CodeMask(A): NEXT
  136.     FOR A = 0 TO 14: READ Powers2(A): NEXT
  137.  
  138.     'get unused file handle
  139.     Handle = FREEFILE
  140.    
  141.     'add GIF extension of needed
  142.     IF INSTR(F$, ".") = 0 THEN F$ = F$ + ".GIF"
  143.    
  144.     'see if file is present
  145.     ErrorStatus = False
  146.     ON ERROR GOTO DriveError
  147.     OPEN F$ FOR INPUT AS Handle
  148.    
  149.     'if not then return with error
  150.     IF ErrorStatus THEN
  151.         ON ERROR GOTO 0
  152.         ErrorStatus = False
  153.         LoadGIF = 1
  154.         CLOSE Handle
  155.         EXIT FUNCTION
  156.     ELSE
  157.         CLOSE Handle
  158.     END IF
  159.     're-open file in binary mode
  160.     OPEN F$ FOR BINARY AS Handle
  161.     ON ERROR GOTO 0
  162.     'just in case it didn't work
  163.     IF ErrorStatus THEN
  164.         ErrorStatus = False
  165.         LoadGIF = 1
  166.         CLOSE Handle
  167.         EXIT FUNCTION
  168.     END IF
  169.   
  170.     'check to see if it's a GIF87a file
  171.     'one of these days I'll implement the GIF89a stuff...
  172.     A$ = SPACE$(6)
  173.     GET Handle, , A$
  174.     IF A$ <> "GIF87a" THEN
  175.         LoadGIF = 2
  176.         CLOSE Handle
  177.         EXIT FUNCTION
  178.     END IF
  179.  
  180.     'get total screen length and width
  181.     GET Handle, , TotalX
  182.     GET Handle, , TotalY
  183.     
  184.     'get number of bits required to represent each pixel
  185.     GET Handle, , ByteBuffer
  186.     A = ASC(ByteBuffer)
  187.     BitsPixel = (A AND 7) + 1
  188.     'check for global color map (if none is present then
  189.     'the default palette, whatever that may be, will be used)
  190.  
  191.         IF (A AND 128) = 0 THEN
  192.         NoPalette = True
  193.     ELSE
  194.         NoPalette = False
  195.     END IF
  196.  
  197.     'get background color
  198.     '(the background color is ignored in this version, it's seldom
  199.     'important so no big loss)
  200.     GET Handle, , ByteBuffer
  201.     BackGround = ASC(ByteBuffer)
  202.     GET Handle, , ByteBuffer
  203.  
  204.     'check to make sure byte 7 of the screen descriptor is 0
  205.     IF ASC(ByteBuffer) <> 0 THEN
  206.         LoadGIF = 2
  207.         CLOSE Handle
  208.         EXIT FUNCTION
  209.     END IF
  210.    
  211.     'calculate the number of colors in image
  212.     NumColors = Powers2(BitsPixel)
  213.     'check out which video mode the caller wants
  214.     SELECT CASE Vm
  215.     CASE 0
  216.         SetMode 0
  217.         ScreenX& = 320 * 256&
  218.         ScreenY& = 200 * 256&
  219.         VGA = True: MaxColors = 256
  220.     CASE 1
  221.         SetMode 1
  222.         SetWidth 90
  223.         ScreenX& = 360 * 256&
  224.         ScreenY& = 480 * 256&
  225.         VGA = True: MaxColors = 256
  226.     CASE 2
  227.         SetMode 2
  228.         SetWidth 80
  229.         ScreenX& = 640 * 256&
  230.         ScreenY& = 480 * 256&
  231.         VGA = True: MaxColors = 16
  232.     CASE 3
  233.         SetMode 2
  234.         SetWidth 40
  235.         ScreenX& = 320 * 256&
  236.         ScreenY& = 200 * 256&
  237.         VGA = False: MaxColors = 16
  238.     CASE 4
  239.         SetMode 2
  240.         SetWidth 80
  241.         ScreenX& = 640 * 256&
  242.         ScreenY& = 350 * 256&
  243.         VGA = False: MaxColors = 16
  244.     END SELECT
  245.     
  246.     'if the video mode selected doesn't have enough colors for the
  247.     'image then return with error
  248.     IF NumColors > MaxColors THEN
  249.         LoadGIF = 3
  250.         CLOSE Handle
  251.         EXIT FUNCTION
  252.     END IF
  253.     
  254.  
  255.     IF NOT NoPalette THEN 'set the palette if it exists
  256.         PalString$ = STRING$(NumColors * 2 + NumColors, 0)
  257.  
  258.         IF ShowType <> 0 THEN
  259.             ShowRGB SADD(PalString$), SSEG(PalString$), NumColors, VGA
  260.         END IF
  261.  
  262.         GET Handle, , PalString$
  263.    
  264.         IF ShowType = 0 THEN
  265.             ShowRGB SADD(PalString$), SSEG(PalString$), NumColors, VGA
  266.         END IF
  267.     END IF
  268.     
  269.     'skip by any GIF extension blocks(some GIF's have them, some don't)
  270.     GET Handle, , ByteBuffer
  271.     DO WHILE ByteBuffer <> ","
  272.         'if not an extension block then return with error
  273.         IF ByteBuffer <> "!" THEN
  274.             LoadGIF = 2
  275.             CLOSE Handle
  276.             EXIT FUNCTION
  277.         ELSE
  278.             'skip the function code
  279.             GET Handle, , ByteBuffer
  280.             'skip by function data bytes
  281.             DO
  282.                 GET Handle, , ByteBuffer
  283.                 BlockLength = ASC(ByteBuffer)
  284.                 A$ = SPACE$(BlockLength)
  285.                 GET Handle, , A$
  286.             LOOP UNTIL BlockLength = 0
  287.         END IF
  288.         GET Handle, , ByteBuffer
  289.     LOOP
  290.  
  291.     '*************************************************************************
  292.     '* X/Y Rescaling Setup Routines Start Here
  293.     '* 7-17-92
  294.  
  295.     'get image start coordinates
  296.     GET Handle, , A: XStart& = A * 256&
  297.     GET Handle, , A: YStart& = A * 256&
  298.     GET Handle, , StoredXLength
  299.     GET Handle, , A
  300.  
  301.     IF XScale = -1 THEN XScale = ScreenX& \ StoredXLength
  302.     IF YScale = -1 THEN YScale = ScreenY& \ A
  303.     
  304.     XLength& = StoredXLength * CLNG(XScale)
  305.     YLength& = A * CLNG(YScale)
  306.     IF XScale <= 1 OR YScale <= 0 OR XLength& > 524288 OR YScale > 4095 THEN
  307.         LoadGIF = 4
  308.         CLOSE Handle
  309.         EXIT FUNCTION
  310.     END IF
  311.  
  312.     XStart& = XStart& + Xorigin * 256&
  313.     YStart& = YStart& + Yorigin * 256&
  314.  
  315.     IF XStart& < 0 THEN
  316.         ArrayOffset = (-XStart&) \ 256
  317.         XLength& = XLength& + XStart&
  318.         XStart& = 0
  319.     ELSE
  320.         ArrayOffset = 0
  321.     END IF
  322.  
  323.     XEnd& = XLength& + XStart& - 256
  324.     YEnd& = YLength& + YStart& - 256
  325.  
  326.     MaxLength = XLength& \ 256
  327.     IF (MaxLength * 256& + XStart& - 256) > ScreenX& THEN
  328.         MaxLength = (ScreenX& - XStart&) \ 256
  329.     END IF
  330.  
  331.     IF XStart& >= ScreenX& OR YStart& >= ScreenY& OR XEnd& < 0 OR YEnd& < 0 OR MaxLength = 0 THEN
  332.         LoadGIF = 4
  333.         CLOSE Handle
  334.         EXIT FUNCTION
  335.     END IF
  336.  
  337.     SkipX = 65536 \ XScale
  338.     SkipY = YScale
  339.     XStart = XStart& \ 256
  340.     ScreenY = ScreenY& \ 256
  341.  
  342.     FOR I = 0 TO 3: READ A: PassStep(I) = A * YScale: NEXT
  343.     FOR I = 0 TO 3: READ A: PassStart(I) = A * YScale + YStart&: NEXT
  344.     '*************************************************************************
  345.     '* X/Y Rescaling Setup Routines End Here
  346.     '*
  347.  
  348.  
  349.     'check for local colormap(I'll handle this as soon as I find
  350.     'a GIF that has one!)
  351.     GET Handle, , ByteBuffer: A = ASC(ByteBuffer)
  352.     IF (A AND 128) THEN
  353.         LoadGIF = 2
  354.         CLOSE Handle
  355.         EXIT FUNCTION
  356.     END IF
  357.  
  358.     'check if interlaced
  359.     IF (A AND 64) THEN
  360.         Interlaced = True
  361.         PassNumber = 0
  362.     ELSE
  363.         Interlaced = False
  364.     END IF
  365.    
  366.     'get LZW minimum code size
  367.     GET Handle, , ByteBuffer
  368.     CodeSize = ASC(ByteBuffer)
  369.    
  370.     'when the clear code is received the LZW vars are reset
  371.     ClearCode = Powers2(CodeSize)
  372.     'when EofCode is received the decompressor stops
  373.     EofCode = ClearCode + 1
  374.     'first free code in table
  375.     FirstFree = ClearCode + 2
  376.     FreeCode = FirstFree
  377.     '# bits in code
  378.     CodeSize = CodeSize + 1
  379.     InitCodeSize = CodeSize
  380.     'maximum # of codes for the current codesize
  381.     MaxCode = MaxCodes(CodeSize - 2)
  382.     BitMask = CodeMask(BitsPixel)
  383.     ReadMask = Masks(CodeSize)
  384.  
  385.     'set up the disk buffer vars
  386.     BitsLeft = 0            'number of bits left(ReadCode)
  387.     BlockLength = 1         'current GIF block length
  388.     Address = 0             'current address in disk buffer
  389.     EndAddress = 1          'address of end of disk buffer
  390.  
  391.     OutCount = 0            '# of pixels in the psuedo-stack
  392.    
  393.     CurrentPixel = 0
  394.     CurrentLine& = YStart&
  395.    
  396.     Done = False
  397.    
  398.     Buffer$ = SPACE$(BufferLength) 'disk buffer
  399.     CodeErrors = 0: ErrorThreshold = 0  'if CodeErrors>ErrorThreshold then
  400.                                         'the image is assumed to be corrupted
  401.     ERASE Pixels
  402.  
  403.     DO 'until an error or EOFCode is detected
  404.  
  405.         'get a code from the data stream- inserted directly into
  406.         'the code to aviod a GOSUB command for each code
  407.     '*************************************************************************
  408.  
  409.         'GOSUB ReadCode
  410.  
  411.         'do we have any bits left?
  412.         IF BitsLeft = 0 THEN
  413.             Address = Address + 1
  414.             IF Address = EndAddress THEN GOSUB FillBuffer
  415.             TempChar = PEEK(Address)
  416.             BlockLength = BlockLength - 1
  417.             IF BlockLength = 0 THEN
  418.                 BlockLength = TempChar
  419.                 Address = Address + 1
  420.                 IF Address = EndAddress THEN GOSUB FillBuffer
  421.                 TempChar = PEEK(Address)
  422.             END IF
  423.             '8 bits left now
  424.             BitsLeft = 8
  425.         END IF
  426.         'attach bits to workcode&
  427.         WorkCode& = TempChar \ Powers2(8 - BitsLeft)
  428.         'loop while more bits are needed...
  429.         DO WHILE CodeSize > BitsLeft
  430.             'get another byte from buffer
  431.             Address = Address + 1
  432.             'fill up buffer if it's empty
  433.             IF Address = EndAddress THEN GOSUB FillBuffer
  434.             TempChar = PEEK(Address)
  435.             'see if at end of current block
  436.             BlockLength = BlockLength - 1
  437.             IF BlockLength = 0 THEN
  438.                 'get another block
  439.                 BlockLength = TempChar
  440.                 Address = Address + 1
  441.                 IF Address = EndAddress THEN GOSUB FillBuffer
  442.                 TempChar = PEEK(Address)
  443.             END IF
  444.             'add bits to workcode&
  445.             WorkCode& = WorkCode& OR TempChar * CLNG(Powers2(BitsLeft))
  446.             BitsLeft = BitsLeft + 8
  447.         LOOP
  448.         'update the BitsLeft variable
  449.         BitsLeft = BitsLeft - CodeSize
  450.         'mask off WorkCode&
  451.         Code = WorkCode& AND ReadMask
  452.  
  453.         
  454. '*************************************************************************
  455.  
  456.  
  457.         'is it an EofCode?
  458.         IF Code <> EofCode THEN
  459.             'check if it's a Clear Code
  460.             IF Code = ClearCode THEN
  461.                 'process a clear code; reset LZW vars
  462.                 CodeSize = InitCodeSize
  463.                 ReadMask = Masks(CodeSize)
  464.                 MaxCode = MaxCodes(CodeSize - 2)
  465.                 FreeCode = FirstFree
  466.                 'first code must be a character
  467.                 GOSUB ReadCode
  468.                 CurCode = Code
  469.                 OldCode = Code
  470.                 FinChar = Code AND BitMask
  471.                 Pixels(CurrentPixel) = FinChar
  472.                 CurrentPixel = CurrentPixel + 1
  473.                 IF CurrentPixel = StoredXLength THEN WriteLine
  474.             ELSE
  475.                 'process a code
  476.                 CurCode = Code
  477.                 InCode = Code
  478.                 'do we have this string yet?
  479.                 IF Code >= FreeCode THEN
  480.                     'Code > FreeCode is invalid: increment CodeErrors and
  481.                     'stop decompression if too many errors(for bum GIF
  482.                     'files)
  483.                     IF Code > FreeCode THEN
  484.                         CodeErrors = CodeErrors + 1
  485.                         IF CodeErrors > ErrorThreshold THEN
  486.                             'trick decompressor into ending early
  487.                             Code = EofCode
  488.                         END IF
  489.                     END IF
  490.                     'trick decompressor into thinking it has just
  491.                     'received the last code
  492.                     CurCode = OldCode
  493.                     OutCode(OutCount) = FinChar
  494.                     OutCount = OutCount + 1
  495.                 END IF
  496.           
  497.                 'does this code represent a string?
  498.                 IF CurCode > BitMask THEN
  499.                     DO 'until we get the last character in this string
  500.                         OutCode(OutCount) = Suffix(CurCode)
  501.                         CurCode = Prefix(CurCode)
  502.                         OutCount = OutCount + 1
  503.                     LOOP UNTIL CurCode <= BitMask  'LOOP until we have one
  504.                 END IF                             'character left
  505.           
  506.                 FinChar = CurCode AND BitMask
  507.                 OutCode(OutCount) = FinChar
  508.                 'plot the pixels; "pop" each one off the stack
  509.                 'when the line buffer is full it will be dumped onto
  510.                 'the screen
  511.                 FOR I = OutCount TO 0 STEP -1
  512.                     Pixels(CurrentPixel) = OutCode(I)
  513.                     CurrentPixel = CurrentPixel + 1
  514.                     IF CurrentPixel = StoredXLength THEN WriteLine
  515.                 NEXT
  516.                 'reset the stack
  517.                 OutCount = 0
  518.                
  519.                 'enter new string into table
  520.                 Prefix(FreeCode) = OldCode
  521.                 Suffix(FreeCode) = FinChar
  522.                 'remember code for later
  523.                 OldCode = InCode
  524.                 FreeCode = FreeCode + 1
  525.                 'increment code size if needed
  526.                 IF FreeCode >= MaxCode AND CodeSize < 12 THEN
  527.                     CodeSize = CodeSize + 1
  528.                     MaxCode = MaxCode * 2
  529.                     ReadMask = ReadMask * 2 OR 1
  530.                 END IF
  531.             END IF
  532.         END IF
  533.     'loop until error or done
  534.     LOOP UNTIL Code = EofCode OR ErrorStatus OR Done
  535.     'close file
  536.     CLOSE Handle
  537.    
  538.     'check for errors
  539.     IF ErrorStatus OR CodeErrors > 0 THEN
  540.         LoadGIF = 5
  541.     ELSE
  542.         IF ShowType = 1 THEN
  543.             ShowRGB SADD(PalString$), SSEG(PalString$), NumColors, VGA
  544.         END IF
  545.         LoadGIF = 0
  546.     END IF
  547.     'all done
  548.     EXIT FUNCTION
  549.  
  550. '*****************************************************************************
  551. '* Reads one code from the GIF data stream
  552. '* BitsLeft    -  # of bits currently left in TempChar
  553. '* TempChar    -  holds the current byte from buffer
  554. '* Address     -  current address in buffer
  555. '* EndAddress  -  end address of buffer
  556. '* BlockLength -  number of bytes left in current block
  557. '* WorkCode&   -  temporary variable;holds current code
  558. '* If this routine was coded in assembly, the decompression speed of this
  559. '* program would probably increase by 100% or more...
  560. ReadCode:
  561.     'do we have any bits left?
  562.     IF BitsLeft = 0 THEN
  563.         Address = Address + 1
  564.         IF Address = EndAddress THEN GOSUB FillBuffer
  565.         TempChar = PEEK(Address)
  566.         BlockLength = BlockLength - 1
  567.         IF BlockLength = 0 THEN
  568.             BlockLength = TempChar
  569.             Address = Address + 1
  570.             IF Address = EndAddress THEN GOSUB FillBuffer
  571.             TempChar = PEEK(Address)
  572.         END IF
  573.         '8 bits left now
  574.         BitsLeft = 8
  575.     END IF
  576.     'attach bits to workcode&
  577.     WorkCode& = TempChar \ Powers2(8 - BitsLeft)
  578.     'loop while more bits are needed...
  579.     DO WHILE CodeSize > BitsLeft
  580.         
  581.         Address = Address + 1   'get another byte from buffer
  582.  
  583.         'fill up buffer if it's empty
  584.         IF Address = EndAddress THEN GOSUB FillBuffer
  585.         TempChar = PEEK(Address)
  586.         
  587.         BlockLength = BlockLength - 1 'see if at end of current block
  588.         IF BlockLength = 0 THEN
  589.             BlockLength = TempChar 'get another block
  590.             Address = Address + 1
  591.             IF Address = EndAddress THEN GOSUB FillBuffer
  592.             TempChar = PEEK(Address)
  593.         END IF
  594.  
  595.         'add bits to workcode&
  596.         WorkCode& = WorkCode& OR TempChar * CLNG(Powers2(BitsLeft))
  597.         BitsLeft = BitsLeft + 8
  598.     LOOP
  599.     
  600.     BitsLeft = BitsLeft - CodeSize 'update the BitsLeft variable
  601.     Code = WorkCode& AND ReadMask  'mask off WorkCode&
  602. RETURN
  603. FillBuffer:
  604.     'fills up the disk buffer
  605.     
  606.     'turn on error checking for this read
  607.     'if an error is detected then main loop will stop decoding the image
  608.  
  609.     ON ERROR GOTO DriveError
  610.     GET Handle, , Buffer$
  611.     ON ERROR GOTO 0
  612.  
  613.     A& = SADD(Buffer$)
  614.     A& = A& - 65536 * (A& < 0)
  615.     DEF SEG = SSEG(Buffer$) + (A& \ 16)
  616.     Address = A& MOD 16
  617.  
  618.     EndAddress = Address + BufferLength
  619. RETURN
  620.  
  621. END FUNCTION
  622.  
  623. SUB WriteLine
  624.     SHARED CurrentPixel, CurrentLine&
  625.     SHARED XStart&, YStart&, YEnd&, ScreenY&
  626.     SHARED MaxLength, XStart, ScreenY, StoredXLength
  627.     SHARED PassNumber, Interlaced, Done
  628.     SHARED SkipX, SkipY
  629.     SHARED ArrayOffset
  630.     DIM ScaledPixels(2047) 'enough to hold 2048 pixels
  631.  
  632.     Y = CurrentLine& \ 256
  633.     Y1 = (CurrentLine& + SkipY) \ 256
  634.     IF SkipX <> 256 THEN
  635.  
  636.         Rescale Pixels(), ScaledPixels(), StoredXLength, SkipX
  637.  
  638.         FOR Y = Y TO Y1 - 1
  639.             IF Y > -1 AND Y < ScreenY THEN
  640.                 SetPixels ArrayOffset, ScaledPixels(), XStart, Y, MaxLength
  641.             END IF
  642.         NEXT
  643.     ELSE
  644.         FOR Y = Y TO Y1 - 1
  645.             IF Y > -1 AND Y < ScreenY THEN
  646.                 SetPixels ArrayOffset, Pixels(), XStart, Y, MaxLength
  647.             END IF
  648.         NEXT
  649.     END IF
  650.     
  651.     CurrentPixel = 0
  652.     IF NOT Interlaced THEN
  653.         CurrentLine& = CurrentLine& + SkipY
  654.         IF CurrentLine& >= ScreenY& THEN Done = True
  655.     ELSE
  656.         CurrentLine& = CurrentLine& + PassStep(PassNumber)
  657.         IF CurrentLine& > YEnd& THEN
  658.             PassNumber = PassNumber + 1
  659.             CurrentLine& = PassStart(PassNumber)
  660.         END IF
  661.         IF PassNumber = 3 AND CurrentLine& >= ScreenY& THEN Done = True
  662.     END IF
  663. END SUB
  664.  
  665.